﻿using System;
using System.Collections.Generic;
using System.Xml;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.Surface.Presentation;
using Microsoft.Surface.Presentation.Controls;

namespace ENMAX_ArcGIS
{
    /// <summary>
    /// A class inherit ScatterView with Drag & Drop support.
    /// </summary>
    public class DragDropScatterView : ScatterView
    {
        public DragDropScatterView()
        {
            // Change Background to transparent, or Drag Drop hit test will by pass it if its Background is null.
            Background = Brushes.Transparent;
            AllowDrop = true;

            Loaded += new RoutedEventHandler(OnLoaded);
            Unloaded += new RoutedEventHandler(OnUnloaded);
        }

        public void RemoveMap(MapFrame deleteMap)
        {
            if (Items.Contains(deleteMap))
                Items.Remove(deleteMap);
        }

        #region Public Properties

        /// <summary>
        /// Property to identify whether the ScatterViewItem can be dragged.
        /// </summary>
        public static readonly DependencyProperty AllowDragProperty = DependencyProperty.Register(
            "AllowDrag",
            typeof(bool),
            typeof(DragDropScatterView),
            new PropertyMetadata(true/*defaultValue*/));

        /// <summary>
        /// Getter of AllowDrag AttachProperty.
        /// </summary>
        /// <param name="element"></param>
        /// <returns></returns>
        public static bool GetAllowDrag(DependencyObject element)
        {
            if (!(element is ScatterViewItem))
            {
                throw new InvalidOperationException("AllowDrag property only works on ScatterViewItem");
            }

            return (bool)element.GetValue(AllowDragProperty);
        }

        /// <summary>
        /// Setter of AllowDrag AttachProperty.
        /// </summary>
        /// <param name="element"></param>
        /// <param name="value"></param>
        public static void SetAllowDrag(DependencyObject element, bool value)
        {
            if (!(element is ScatterViewItem))
            {
                throw new InvalidOperationException("AllowDrag property only works on ScatterViewItem");
            }

            element.SetValue(AllowDragProperty, value);
        }

        #endregion

        #region Private Methods

        private void OnLoaded(object sender, RoutedEventArgs e)
        {
            SurfaceDragDrop.AddDropHandler(this, OnCursorDrop);
                      
            AddHandler(ScatterViewItem.ScatterManipulationStartedEvent, new ScatterManipulationStartedEventHandler(OnManipulationStarted));
        }

        private void OnUnloaded(object sender, RoutedEventArgs e)
        {
            SurfaceDragDrop.RemoveDropHandler(this, OnCursorDrop);
            RemoveHandler(ScatterViewItem.ScatterManipulationStartedEvent, new ScatterManipulationStartedEventHandler(OnManipulationStarted));
        }

        private void OnManipulationStarted(object sender, RoutedEventArgs args)
        {
            ScatterViewItem svi = args.OriginalSource as ScatterViewItem;
            if (svi != null && DragDropScatterView.GetAllowDrag(svi))
            {
                svi.BeginDragDrop(svi.DataContext);
            }
        }

        private void OnCursorDrop(object sender, SurfaceDragDropEventArgs args)
        {
            SurfaceDragCursor droppingCursor = args.Cursor;

            // Add dropping Item that was from another drag source.
            if (droppingCursor.CurrentTarget == this && droppingCursor.DragSource != this)
            {
                ContentControl cursorVisual = droppingCursor.Visual as ContentControl;
                if (cursorVisual != null)
                {
                    MapFrame mapFrame = createMapFrameToDrop(cursorVisual);
                    if (mapFrame == null)
                    {
                        return;
                    }

                    // Modify IsActive to give it a bouncing effect when it lands
                    mapFrame.IsActive = true;
                    Items.Add(mapFrame);
                    mapFrame.IsActive = false;

                    mapFrame.Center = droppingCursor.GetPosition(this);
                    mapFrame.Orientation = droppingCursor.GetOrientation(this);
                    mapFrame.SetRelativeZIndex(RelativeScatterViewZIndex.Topmost);

                    mapFrame.BringIntoView();                    

                    // drop highlighting
                    HighlightScatterView(false);

                    args.Effects = DragDropEffects.Move;
                    args.Handled = true;
                    
                }
            }
        }

        /// <summary>
        /// Highlights a target control by changing the BorderBrush.
        /// </summary>
        /// <param name="target"></param>
        /// <param name="highlight"></param>
        private void HighlightScatterView(bool highlight)
        {
            if (highlight)
            {
                // hightlight the target control if this is the first object over it
                if (SurfaceDragDrop.GetTargetedCursors(this,true).Count == 1)
                {
                    BorderBrush = Brushes.Pink;
                }
            }
            else
            {
                // remove highlighting from the target control if this is the last object over it
                if (!SurfaceDragDrop.GetIsAnyCursorTargeted(this))
                {
                    BorderBrush = null;
                }
            }
        }

        /// <summary>
        /// Creates a MapFrame object to drop in the scatterview 
        /// </summary>
        /// <param name="draggedCursor"></param>
        /// <returns></returns>
        private MapFrame createMapFrameToDrop(ContentControl draggedCursor)
        {
            // Get Xml source.
            XmlElement sourceData = draggedCursor.DataContext as XmlElement;
            if (sourceData == null)
            {
                return null;
            }
            
            // Get the image path out of the source's contents            
            string imageName = sourceData.GetAttribute("Name");
            // TODO: figure out the complete path
            string imagePath = sourceData.GetAttribute("Image");

            PanelPictureMap pictureMap = PanelPictureMap.createPanelPictureMap(imageName, imagePath);
            MapFrame svi = new MapFrame(this, pictureMap);
            svi.DataContext = draggedCursor.DataContext;            
            return svi;
        }


        #endregion
    }
}
